package com.ruoyi.system.controller;

import java.io.*;
import java.security.SecureRandom;
import java.util.*;
import java.util.List;
import javax.servlet.http.HttpServletResponse;

import com.ruoyi.system.domain.MyTask;
import com.ruoyi.system.util.ResObject;
import org.apache.poi.util.IOUtils;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.beans.BeanUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.system.domain.HcApplydan;
import com.ruoyi.system.service.IHcApplydanService;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.common.core.page.TableDataInfo;

/**
 * Controller
 * 
 * @author ruoyi
 * @date 2023-03-31
 */
@RestController
@RequestMapping("/system/applydan")
public class HcApplydanController extends BaseController implements Serializable
{
    @Autowired
    private IHcApplydanService hcApplydanService;

    private static final String SYMBOLS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // 数字和26个字母组成
    private static final Random RANDOM = new SecureRandom();

    @Autowired
    private RepositoryService repositoryService;

    //启动一个流程实例
    @Autowired
    private RuntimeService runtimeService;

    //查询分配给某人或一组的任务,产生独立的任务,不依赖于任何流程实例的任务，流程实例需要等待一个外部触发,从而继续执行
    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private ProcessEngine processEngine;

    /**
     * 查询列表
     */
    @PreAuthorize("@ss.hasPermi('system:applydan:list')")
    @GetMapping("/list")
    public TableDataInfo list(HcApplydan hcApplydan)
    {
        startPage();
        List<HcApplydan> list = hcApplydanService.selectHcApplydanList(hcApplydan);
        return getDataTable(list);
    }

    /**
     * 导出列表
     */
    @PreAuthorize("@ss.hasPermi('system:applydan:export')")
    @Log(title = "", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, HcApplydan hcApplydan)
    {
        List<HcApplydan> list = hcApplydanService.selectHcApplydanList(hcApplydan);
        ExcelUtil<HcApplydan> util = new ExcelUtil<HcApplydan>(HcApplydan.class);
        util.exportExcel(response, list, "数据");
    }

    /**
     * 获取详细信息
     */
    @PreAuthorize("@ss.hasPermi('system:applydan:query')")
    @GetMapping(value = "/{id}")
    public AjaxResult getInfo(@PathVariable("id") Long id)
    {
        return AjaxResult.success(hcApplydanService.selectHcApplydanById(id));
    }

    /**
     * 新增
     */
   // @PreAuthorize("@ss.hasPermi('system:applydan:add')")
    @Log(title = "添加", businessType = BusinessType.INSERT)
    @PostMapping
    public String add (@RequestBody HcApplydan hcApplydan)
    {
        System.out.println("add something   "+hcApplydan);
        String result =getRandomNumber();
        hcApplydan.setAid(result);
        hcApplydanService.insertHcApplydan(hcApplydan);
        //部署流程test-first.bpmn20.xml
        Deployment deploy = repositoryService.createDeployment().addClasspathResource("processes/test-first.bpmn20.xml").deploy();
        //查找部署流程的定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult();

        Map<String, Object> variables = new HashMap<>();
        variables.put("aid", hcApplydan.getAid());
        variables.put("kname", hcApplydan.getKname());
        variables.put("person", hcApplydan.getPerson());
        variables.put("time", hcApplydan.getTime());
        variables.put("nextUser1", "科室库主任");
        variables.put("nextUser2", "中心库主任");
        variables.put("nextUser3", "库房管理员");
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("test-first-model-key",variables);

        System.err.println("提交成功："+processInstance.getProcessInstanceId()+" "+processInstance.getId());

        /*variables.put("processInstanceId", );
        variables.put("executionId", );
        variables.put("taskDefinitionId", );
        variables.put("processDefinitionId", );*/

        return result;
    }

    @PostMapping("/find")
    public ResObject find(@RequestBody HcApplydan hcApplydan) {
        System.out.println("********************"+hcApplydan.toString()+"********************");
        System.out.println("参数=>"+hcApplydan.getAid()+hcApplydan.getTime());
        List<Task> tasks = taskService.createTaskQuery().taskAssignee(hcApplydan.getAssignee()).list();
        for(Task task:tasks) {
            System.out.println("taskId:"+task.getId()+",taskName:"+task.getName()+",getProcessInstanceId():"+task.getProcessInstanceId());
        }
        List<MyTask> myTasks = new ArrayList<>(tasks.size());
        tasks.forEach(item -> {
            MyTask myTask = new MyTask();
            Map<String, Object> variables = taskService.getVariables(item.getId());
            System.out.println("************variable************");
            System.out.println(variables);
            //System.out.println(variables.get("kname"));
            //String name= (String) variables.get("kname");
            myTask.setAid((String) variables.get("aid"));
            myTask.setKname((String) variables.get("kname"));
            myTask.setPerson((String) variables.get("person"));
            myTask.setTime((Date) variables.get("time"));
            BeanUtils.copyProperties(item, myTask);
            myTasks.add(myTask);
        });
        System.out.println("**********myTask**********");
        System.out.println(myTasks.toString());
        //第二种写法(不能驳回,待解决)
        /*List<Map<String, Object>> list = new ArrayList<>();
        for (int i = 0; i < tasks.size(); i++) {
            Task task = tasks.get(i);
            Map<String, Object> variables = taskService.getVariables(task.getId());

            variables.put("id", task.getId());
            list.add(variables);
        }
        System.err.println("************list*********");
        System.out.println(list.toString());*/

        return new ResObject(myTasks);
    }

    @PostMapping("/agree")
    public ResObject agree(@RequestBody MyTask myTask) {
        taskService.complete(myTask.getId());
        return new ResObject();
    }
    @ResponseBody
    @PostMapping(value="/reject")
    public ResObject reject(@RequestBody MyTask task) {
        System.out.println("驳回===="+task.toString());
        String processInstanceId=task.getProcessInstanceId();
        String executionId=task.getExecutionId();
        if(processInstanceId==null||executionId==null) {
            System.out.println("processInstanceId==null"+" "+executionId);
        }

        String currentActivityId = runtimeService.getActiveActivityIds(executionId).get(0);
        String lastActivityId = getLastActivityId(processInstanceId, currentActivityId);
        //回退了 流程
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(processInstanceId)
                .moveActivityIdTo(currentActivityId, lastActivityId)
                .changeState();

        return new ResObject();
    }

    private String getLastActivityId(String processInstanceId, String currentActivityId) {

        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .finished()
                .activityType("userTask")
                .orderByHistoricActivityInstanceStartTime().desc()
                .list();


        String lastActivityId = null;
        //找到上一个流程的 activityId
        for (int i=0; i<list.size(); i++) {
            HistoricActivityInstance activityInstance = list.get(i);
            if(activityInstance.getActivityId().equals(currentActivityId)) {
                lastActivityId = list.get(++i).getActivityId();
                break;
            }
        }

        if(lastActivityId == null) {
            lastActivityId = list.get(0).getActivityId();
        }

        return lastActivityId;
    }

    /**
     * 获取长度为 6 的随机字母+数字
     * @return 随机数字
     */
    public static String getRandomNumber() {
        char[] nonceChars = new char[6];  //指定长度为6位/自己可以要求设置

        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }
    /**
     * 修改
     */
    @PreAuthorize("@ss.hasPermi('system:applydan:edit')")
    @Log(title = "", businessType = BusinessType.UPDATE)
    @PutMapping
    public AjaxResult edit(@RequestBody HcApplydan hcApplydan)
    {
        return toAjax(hcApplydanService.updateHcApplydan(hcApplydan));
    }

    /**
     * 删除
     */
    @PreAuthorize("@ss.hasPermi('system:applydan:remove')")
    @Log(title = "", businessType = BusinessType.DELETE)
	@DeleteMapping("/{ids}")
    public AjaxResult remove(@PathVariable Long[] ids)
    {
        return toAjax(hcApplydanService.deleteHcApplydanByIds(ids));
    }
    //生成流程图图片

    /**
     * 生成流程图
     *
     */
    @PostMapping(value = "processDiagram")
    public void genProcessDiagram_(HttpServletResponse httpServletResponse, @RequestBody MyTask params) throws Exception {
        System.out.println(params);
        String processId=params.getProcessDefinitionId();
        String processInstanceId=params.getProcessInstanceId();
        System.out.println(processId+" "+processInstanceId);
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();

        //流程走完的不显示图
        if (pi == null) {
            return ;
        }
        //FileUtils.copyInputStreamToFile(in, new File("D:/process-diagram.png"));

        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
        //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        String InstanceId = task.getProcessInstanceId();
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(InstanceId)
                .list();

        //得到正在执行的Activity的Id
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }

        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(params.getProcessDefinitionId());
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png",
                activityIds, flows, "宋体","宋体","宋体",null,1.0, false);
        // 将流程图转换为PNG格式并发送给HTTP响应
        //InputStream processDiagram = processEngine.getRepositoryService().getProcessDiagram(pi.getProcessDefinitionId());
        byte[] bytes = IOUtils.toByteArray(in);
        /*httpServletResponse.setContentType("image/png");
        ServletOutputStream outputStream = httpServletResponse.getOutputStream();
        outputStream.write(bytes);
        outputStream.flush();
        outputStream.close();*/
        //输出为图片
        // 将byte[]转换成Base64编码的字符串
        String base64Img = Base64.getEncoder().encodeToString(bytes);

        // 将base64Img发送给前端，例如通过HTTP响应输出
        httpServletResponse.setContentType("text/html;charset=utf-8");
        PrintWriter output = httpServletResponse.getWriter();
        System.out.println(base64Img);
        output.println("<img src=\"data:image/png;base64," + base64Img + "\" />");
    }

    /**
     * 生成流程图
     *
     * @param processId 任务ID
     */
    @GetMapping("/diagram/{processId}")
    public ResponseEntity<byte[]> genProcessDiagram(HttpServletResponse httpServletResponse,
                                  @PathVariable("processId") String processId) throws Exception {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();

        //流程走完的不显示图
        if (pi == null) {
            return  null;
        }
        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
        //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        String InstanceId = task.getProcessInstanceId();
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(InstanceId)
                .list();

        //得到正在执行的Activity的Id
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }

        //获取流程图

        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png",
                activityIds, flows, "宋体","宋体","宋体",null,1.0, false);
        //httpServletResponse.setContentType("image/jpeg"); // 指定响应类型为图片
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = httpServletResponse.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.IMAGE_JPEG);
        return new ResponseEntity<>(buf, headers, HttpStatus.OK);
    }
 // 源码 www.1b23.com
    /*public byte[] createImage2(String processInstanceId) {
            //1.获取当前的流程实例
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            String processDefinitionId = null;
            List<String> activeActivityIds = null;
            //2.获取所有的历史轨迹对象
            List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(processInstanceId).list();
            Map<String, HistoricActivityInstance> hisActivityMap = new HashMap<>();
            list.forEach(historicActivityInstance -> {
                if (!hisActivityMap.containsKey(historicActivityInstance.getActivityId())) {
                    hisActivityMap.put(historicActivityInstance.getActivityId(), historicActivityInstance);
                }
            });
            //3. 获取流程定义id和高亮的节点id
            if (processInstance != null) {
                //3.1. 正在运行的流程实例
                processDefinitionId = processInstance.getProcessDefinitionId();
                activeActivityIds = runtimeService.getActiveActivityIds(processInstanceId);
            } else {
                //3.2. 已经结束的流程实例
                HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
                processDefinitionId = historicProcessInstance.getProcessDefinitionId();
                activeActivityIds = new ArrayList<>();
                List<EndEvent> endEvents = bpmnModelService.findEndFlowElement(processDefinitionId);
                List<String> finalActiveActivityIds = activeActivityIds;
                endEvents.forEach(endEvent -> {
                    if (hisActivityMap.containsKey(endEvent.getId())) {
                        finalActiveActivityIds.add(endEvent.getId());
                    }
                });
            }
            //4. 获取流程定义的所有节点信息
            List<FlowNode> flowNodes = bpmnModelService.findFlowNodes(processDefinitionId);
            Map<String, FlowNode> activityMap = flowNodes.stream().collect(Collectors.toMap(FlowNode::getId, flowNode -> flowNode));
            List<String> highLightedFlows = new ArrayList<>();
            //5. 递归得到高亮线
            activeActivityIds.forEach(activeActivityId -> this.getHighLightedFlows(activityMap, hisActivityMap, activeActivityId, highLightedFlows, activeActivityId));
            //6. 获取bpmnModel对象
            BpmnModel bpmnModel = bpmnModelService.getBpmnModelByProcessDefId(processDefinitionId);
            //7. 生成图片流
            InputStream inputStream = flowProcessDiagramGenerator.generateDiagram(bpmnModel, activeActivityIds, highLightedFlows);
            //8. 转化成byte便于网络传输
            byte[] datas = IoUtil.readInputStream(inputStream, "image inputStream name");
            return datas;
        }*/

      //www.1b23.com
/*private void getHighLightedFlows(Map<String, FlowNode> flowNodeMap,
            Map<String, HistoricActivityInstance> hisActivityMap,
            String activeActivityId,
            List<String> highLightedFlows,
            String oldActivityId) {
        FlowNode flowNode = flowNodeMap.get(activeActivityId);
        List<SequenceFlow> incomingFlows = flowNode.getIncomingFlows();
        for (SequenceFlow sequenceFlow : incomingFlows) {
            String sourceRefId = sequenceFlow.getSourceRef();
            if (hisActivityMap.containsKey(sourceRefId) && !oldActivityId.equals(sourceRefId)) {
                highLightedFlows.add(sequenceFlow.getId());
                this.getHighLightedFlows(flowNodeMap, hisActivityMap, sourceRefId, highLightedFlows, oldActivityId);
            } else {
　
　　　　　　　　　　if (hisActivityMap.containsKey(sourceRefId)){
　　　　　　　　　　　　　　highLightedFlows.add(sequenceFlow.getId());
　　　　　　　　　　}
　　　　　　　　　　break;
	} } }*/

}
